#ifndef AUBO_PI_PROFINET_DEVICE_H
#define AUBO_PI_PROFINET_DEVICE_H

#include <QFile>
#include <QTextStream>
#include <QSharedMemory>

#include "p-net/osal.h"
#include "p-net/pnet_api.h"

namespace aubo
{

namespace pi
{

extern QFile file_log;
extern QTextStream text_stream;

/********************** Settings **********************************************/

#define EVENT_READY_FOR_DATA BIT(0)
#define EVENT_TIMER BIT(1)
#define EVENT_ALARM BIT(2)
#define EVENT_ABORT BIT(15)

#define TICK_INTERVAL_US 1000   /* 1 ms */
// #define TICK_INTERVAL_US 5000   /* 5 ms */
// #define TICK_INTERVAL_US 10000   /* 10 ms */
#define APP_ALARM_USI 1

/**************** From the GSDML file ****************************************/

// #define APP_DEFAULT_STATION_NAME "aubo-robotics-dev"
// #define APP_DEFAULT_STATION_NAME "rt-labs-dev"
#define APP_PARAM_IDX_1 123
#define APP_PARAM_IDX_2 124
#define APP_API 0

/*
 * Module and submodule ident number for the DAP module.
 * The DAP module and submodules must be plugged by the application after the call to pnet_init.
 */
#define PNET_SLOT_DAP_IDENT                        0x00000000
#define PNET_MOD_DAP_IDENT                         0x00000001     /* For use in slot 0 */
#define PNET_SUBMOD_DAP_IDENT                      0x00000001     /* For use in subslot 1 */
#define PNET_SUBMOD_DAP_INTERFACE_1_IDENT          0x00008000     /* For use in subslot 0x8000 */
#define PNET_SUBMOD_DAP_INTERFACE_1_PORT_0_IDENT   0x00008001     /* For use in subslot 0x8001 */

/*
 * I/O Modules. These modules and their sub-modules must be plugged by the
 * application after the call to pnet_init.
 *
 * Assume that all modules only have a single submodule, with same number.
 */
#define PNET_MOD_R2C_SYSTEM_STATE_IDENT     0x00000030     // Robot --> PLC Controller: Input: Robot's system state.
#define PNET_MOD_R2C_IO_STATE_IDENT         0x00000031     // Robot --> PLC Controller: Input: Robot's IO state.
#define PNET_MOD_R2C_JOINT_STATE_IDENT      0x00000032     // Robot --> PLC Controller: Input: Robot's joint state.
#define PNET_MOD_USER_DEFINITION_IDENT      0x00000033     // Input & Output: User-defined register.
#define PNET_SUBMOD_CUSTOM_IDENT            0x00000001

#define APP_ALARM_PAYLOAD_SIZE 1     /* bytes */


/*** Example on how to keep lists of supported modules and submodules ********/
// 模块、子模块
static const uint32_t cfg_available_module_types[] =
{
    PNET_MOD_DAP_IDENT,
    PNET_MOD_R2C_SYSTEM_STATE_IDENT,
    PNET_MOD_R2C_IO_STATE_IDENT,
    PNET_MOD_R2C_JOINT_STATE_IDENT,
    PNET_MOD_USER_DEFINITION_IDENT,
};

static const struct
{
    uint32_t api;
    uint32_t module_ident_nbr;
    uint32_t submodule_ident_nbr;
    pnet_submodule_dir_t data_dir;
    uint16_t insize;     /* bytes */
    uint16_t outsize;    /* bytes */
} cfg_available_submodule_types[] =
{
    {APP_API, PNET_MOD_DAP_IDENT, PNET_SUBMOD_DAP_IDENT, PNET_DIR_NO_IO, 0, 0},
    {APP_API, PNET_MOD_DAP_IDENT, PNET_SUBMOD_DAP_INTERFACE_1_IDENT, PNET_DIR_NO_IO, 0, 0},
    {APP_API, PNET_MOD_DAP_IDENT, PNET_SUBMOD_DAP_INTERFACE_1_PORT_0_IDENT, PNET_DIR_NO_IO, 0, 0},

    {APP_API, PNET_MOD_R2C_SYSTEM_STATE_IDENT, PNET_SUBMOD_CUSTOM_IDENT, PNET_DIR_INPUT, 32, 0},
    {APP_API, PNET_MOD_R2C_IO_STATE_IDENT, PNET_SUBMOD_CUSTOM_IDENT, PNET_DIR_INPUT, 32, 0},
    {APP_API, PNET_MOD_R2C_JOINT_STATE_IDENT, PNET_SUBMOD_CUSTOM_IDENT, PNET_DIR_INPUT, 128, 0},
    {APP_API, PNET_MOD_USER_DEFINITION_IDENT, PNET_SUBMOD_CUSTOM_IDENT, PNET_DIR_IO, 128, 128},
};

/************************ App data storage ***********************************/

typedef struct app_data_obj
{
    os_timer_t * main_timer;
    os_event_t * main_events;
    uint32_t main_arep;
    bool alarm_allowed;
    // uint32_t                  app_param_1;
    // uint32_t                  app_param_2;
    // uint8_t                   custom_input_slots[PNET_MAX_MODULES];
    // uint8_t                   custom_output_slots[PNET_MAX_MODULES];
    bool init_done;

    // 用户数据，用于设置初始值.
    uint8_t robot_system_state[32];
    uint8_t robot_io_state[32];
    uint8_t robot_joint_state[128];
    uint8_t user_definition_input[128];
    uint8_t user_definition_output[128];
    uint8_t interconnection_status[16];     // 该软件与遨博机械臂插件之间的通信状态。

    // 进程间数据共享。
    // boost::shared_ptr<boost::interprocess::managed_shared_memory> msm_segment;
    // boost::shared_ptr<boost::interprocess::named_mutex> msm_mutex;
    QSharedMemory * shm_robot_system_state_;
    QSharedMemory * shm_robot_io_state_;
    QSharedMemory * shm_robot_joint_state_;
    QSharedMemory * shm_user_definition_input_;
    QSharedMemory * shm_user_definition_output_;
    QSharedMemory * shm_profinet_state_;

} app_data_t;


typedef struct app_data_and_stack_obj
{
    app_data_t * appdata;
    pnet_t * net;
} app_data_and_stack_t;


/********************* Helper function declarations ***************************/

// 时钟响应函数。
void mainTimerTick(os_timer_t * os_timer, void * arg);

// 配置协议栈参数。
int pnetAdjustStackConfiguration(pnet_cfg_t * stack_config);

// 插入槽、模块。
bool pnetPlugDAP(pnet_t * net, void * arg);     // DAP: Device Access Point.
// Profinet通信主循环，根据状态进行操作。
void pnetMainLoop(void * arg);

// 回调函数，供Profinet协议栈使用。
int pnetConnectInd(pnet_t * net, void * arg, uint32_t arep, pnet_result_t * p_result);
int pnetReleaseInd(pnet_t * net, void * arg, uint32_t arep, pnet_result_t * p_result);
int pnetDControlInd(pnet_t * net, void * arg, uint32_t arep,
        pnet_control_command_t ctrl_command, pnet_result_t * p_result);
int pnetCControlInd(pnet_t * net, void * arg, uint32_t arep, pnet_result_t * p_result);
int pnetStateInd(pnet_t * net, void * arg, uint32_t arep, pnet_event_values_t state);
int pnetReadInd(pnet_t * net, void * arg, uint32_t arep,
        uint32_t api, uint16_t slot, uint16_t subslot, uint16_t idx, uint16_t sequence_number,
        uint8_t ** pp_read_data, uint16_t * p_read_length, pnet_result_t * p_result);
int pnetWriteInd(pnet_t * net, void * arg, uint32_t arep,
        uint32_t api, uint16_t slot, uint16_t subslot, uint16_t idx, uint16_t sequence_number,
        uint16_t write_length, uint8_t * p_write_data, pnet_result_t * p_result);
int pnetExpModuleInd(pnet_t * net, void * arg,
        uint32_t api, uint16_t slot, uint32_t module_ident);
int pnetExpSubmoduleInd(pnet_t * net, void * arg,
        uint32_t api, uint16_t slot, uint16_t subslot, uint32_t module_ident, uint32_t submodule_ident);
int pnetNewDataStatusInd(pnet_t * net, void * arg, uint32_t arep,
        uint32_t crep, uint8_t changes, uint8_t data_status);
int pnetAlarmInd(pnet_t * net, void * arg, uint32_t arep,
        uint32_t api, uint16_t slot, uint16_t subslot, uint16_t data_len, uint16_t data_usi, uint8_t * p_data);
int pnetAlarmCnf(pnet_t * net, void * arg, uint32_t arep, pnet_pnio_status_t * p_pnio_status);
int pnetAlarmAckCnf(pnet_t * net, void * arg, uint32_t arep, int res);
int pnetResetInd(pnet_t * net, void * arg, bool should_reset_application, uint16_t reset_mode);


} // namespace pi

} // namespace aubo

#endif // AUBO_PI_PROFINET_DEVICE_H
